package com.springboot.fastcode.generate.service.impl;

import com.springboot.fastcode.common.GenerateSuffixConstants;
import com.springboot.fastcode.common.GenerateMysqlType2JavaTypeEnums;
import com.springboot.fastcode.common.GenerateTemplatePathConstants;
import com.springboot.fastcode.common.entity.FieldInfo;
import com.springboot.fastcode.common.properties.GenerateProperties;
import com.springboot.fastcode.config.FreeMarkerInit;
import com.springboot.fastcode.generate.dto.GenerateCodeDto;
import com.springboot.fastcode.generate.service.GenerateCodeService;
import com.springboot.fastcode.utils.FieldConvertJavaHumpUtils;
import com.springboot.fastcode.utils.DBUtils;
import com.springcloud.common.utils.BeanCopyUtil;
import com.springcloud.common.utils.ZipUtils;
import com.springcloud.common.vo.SelectFormatVO;
import freemarker.template.Template;
import freemarker.template.TemplateException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.sql.DataSource;
import java.io.*;
import java.sql.SQLException;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author liaofuxing
 * @E-mail liaofuxing@outlook.com
 * @date 2020/05/17 18:38
 **/
@Service
public class GenerateCodeServiceImpl implements GenerateCodeService {

    @Autowired
    private FreeMarkerInit freeMarkerInit;

    @Autowired
    private DataSource dataSource;

    @Autowired
    private GenerateProperties generateProperties;

    /**
     * 获取数据库表
     * @return List<SelectFormatVO> 表集合
     * @throws SQLException sql执行异常
     */
    public List<SelectFormatVO> getTableSelect() throws SQLException {
        DBUtils dbUtils = new DBUtils(dataSource);
        List<String> tableList = dbUtils.getTableList();
        List<SelectFormatVO> selectFormatVOList = new ArrayList<>();
        for (String tableName: tableList ) {
            SelectFormatVO selectFormatVO = new SelectFormatVO(tableName,tableName );
            selectFormatVOList.add(selectFormatVO);
        }
        return selectFormatVOList;
    }

    @Override
    public List<FieldInfo> getTableField(String tableName) throws SQLException {
        List<FieldInfo> tableFields = null;
        try {
            DBUtils dbUtils = new DBUtils(dataSource);
            tableFields = dbUtils.getDBFieldList(tableName);
            for (FieldInfo fieldInfo: tableFields) {
                // mysql列风格转换java驼峰风格
                String javaHumpField = FieldConvertJavaHumpUtils.firstCodeLowerCaseConvertJavaHump(fieldInfo.getDbColumnName());
                // mysql类型转java类型
                String javaType = GenerateMysqlType2JavaTypeEnums.getJavaType(fieldInfo.getDbColumnType());
                fieldInfo.setJavaHumpColumnName(javaHumpField);
                fieldInfo.setJavaColumnType(javaType);
            }
        }catch (SQLException e){
            e.printStackTrace();
            throw e;
        }
        return tableFields;
    }

    @Override
    public void generateCode(GenerateCodeDto generateCodeDto, String token) throws IOException, TemplateException {
        Map<String, String> pathMap = generateCodeFileDir(generateCodeDto.getPackagePath(), token);
        String sourceDirPath = pathMap.get("sourceDirPath");
        String zipDirPath = pathMap.get("zipDirPath");

        Map<String, Map<String, Object>> generatePublicParamMap = generatePublicParam(generateCodeDto);

        if(generateCodeDto.getOnlyGenerateJavaBean()) {
            onlyGenerateJavaBean(generateCodeDto, generatePublicParamMap, sourceDirPath);
        }else {
            generateCodeAll(generateCodeDto, generatePublicParamMap, sourceDirPath);
        }

        // zip OutputStream eg: this zip file  writer path : "F://xxx/xxx.zip"
        FileOutputStream fos1 = new FileOutputStream(new File(  zipDirPath + GenerateSuffixConstants.PATH_SIGN_SUFFIX + generateCodeDto.getTableName() + GenerateSuffixConstants.ZIP_FILE_SUFFIX));

        ZipUtils.toZip(generateProperties.getGenerateFileRootPath()
                        + GenerateSuffixConstants.PATH_SIGN_SUFFIX
                        +token+GenerateSuffixConstants.PATH_SIGN_SUFFIX,
                fos1, true);
    }

    /**
     * 仅生成java bean
     * @param generateCodeDto dto
     * @param generatePublicParamMap 公共模板参数map
     * @param sourceDirPath 源码输出路径
     * @throws IOException io 异常
     * @throws TemplateException 模板异常
     */
    public void onlyGenerateJavaBean(GenerateCodeDto generateCodeDto,
                                     Map<String, Map<String, Object>> generatePublicParamMap,
                                     String sourceDirPath) throws IOException, TemplateException {
        generateEntity(generateCodeDto, generatePublicParamMap, sourceDirPath, "classpath:templates/jpa/entity", GenerateTemplatePathConstants.ENTITY_TEMPLATE_NAME);
    }

    /**
     * 仅生成所有代码
     * @param generateCodeDto dto
     * @param generatePublicParamMap 公共模板参数map
     * @param sourceDirPath 源码输出路径
     * @throws IOException io 异常
     * @throws TemplateException 模板异常
     */
    public void generateCodeAll(GenerateCodeDto generateCodeDto,
                                     Map<String, Map<String, Object>> generatePublicParamMap,
                                     String sourceDirPath) throws IOException, TemplateException {
        onlyGenerateJavaBean(generateCodeDto, generatePublicParamMap, sourceDirPath);

        generateDto(generateCodeDto, generatePublicParamMap, sourceDirPath, "classpath:templates/jpa/dto", GenerateTemplatePathConstants.ENTITY_DTO_TEMPLATE_NAME);

        generateVo(generateCodeDto, generatePublicParamMap, sourceDirPath, "classpath:templates/jpa/vo", GenerateTemplatePathConstants.ENTITY_VO_TEMPLATE_NAME);

        generateDao(generateCodeDto, generatePublicParamMap, sourceDirPath, "classpath:templates/jpa/dao", GenerateTemplatePathConstants.DAO_TEMPLATE_NAME);

        generateService(generateCodeDto, generatePublicParamMap, sourceDirPath, "classpath:templates/jpa/service", GenerateTemplatePathConstants.SERVICE_TEMPLATE_NAME);

        generateServiceImpl(generateCodeDto, generatePublicParamMap, sourceDirPath, "classpath:templates/jpa/service/impl", GenerateTemplatePathConstants.SERVICE_IMPL_TEMPLATE_NAME);

        generateController(generateCodeDto, generatePublicParamMap, sourceDirPath, "classpath:templates/jpa/web", GenerateTemplatePathConstants.CONTROLLER_TEMPLATE_NAME);

    }


    /**
     * 创建源码文件夹
     * @param packagePath 包路径
     * @param token 用户token
     * @return Map<String, String>
     */
    public Map<String, String> generateCodeFileDir(String packagePath, String token) {
        String generateFileRootPath = generateProperties.getGenerateFileRootPath() + GenerateSuffixConstants.PATH_SIGN_SUFFIX + token;
        String[] packagePathArr = packagePath.split("\\.");
        StringBuilder packagePathDir = new StringBuilder(GenerateSuffixConstants.PATH_SIGN_SUFFIX);
        for (String packagePathStr: packagePathArr) {
            packagePathDir.append(packagePathStr).append(GenerateSuffixConstants.PATH_SIGN_SUFFIX);
        }
        String generatePath = generateFileRootPath + packagePathDir.toString();

        List<String> mkdirPathList = new ArrayList<>();
        mkdirPathList.add(generatePath + GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.ENTITY_PATH_SUFFIX);
        mkdirPathList.add(generatePath + GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.SERVICE_PATH_SUFFIX);
        mkdirPathList.add(generatePath + GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.SERVICE_IMPL_PATH_SUFFIX);
        mkdirPathList.add(generatePath + GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.DAO_PATH_SUFFIX);
        mkdirPathList.add(generatePath + GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.DTO_PATH_SUFFIX);
        mkdirPathList.add(generatePath + GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.VO_PATH_SUFFIX);
        mkdirPathList.add(generatePath + GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.CONTROLLER_PATH_SUFFIX);


        // mkdirs dir
        for (String mkdirPath: mkdirPathList) {
            File file = new File(mkdirPath);
            if(!file.exists() && !file.isDirectory()) {
                file.mkdirs();
            }
        }

        // mkdir zip dir
        String generateFileRootPathZip = generateProperties.getGenerateFileRootPath()
                + GenerateSuffixConstants.PATH_SIGN_SUFFIX
                + token
                + GenerateSuffixConstants.ZIP_PATH_SUFFIX;

        //String sourceDirPath = generatePath + GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.ENTITY_PATH_SUFFIX;
        File fileZip = new File(generateFileRootPathZip);
        if(!fileZip.exists() && !fileZip.isDirectory()) {
            fileZip.mkdir();
        }
        HashMap<String, String> pathMap = new HashMap<>();
        pathMap.put("sourceDirPath", generatePath);
        pathMap.put("zipDirPath", generateFileRootPathZip);
        return pathMap;
    }

    /**
     * 生成 entity
     * @param generateCodeDto dto
     * @param generatePublicParamMap 公共模板参数
     * @param sourceDirPath 源码输出路径
     * @param templatePath 模板路劲
     * @param templateName 模板文件名
     * @throws IOException io异常
     * @throws TemplateException 模板异常
     */
    public void generateEntity(GenerateCodeDto generateCodeDto,
                               Map<String, Map<String, Object>> generatePublicParamMap,
                               String sourceDirPath,
                               String templatePath,
                               String templateName) throws IOException, TemplateException {

        sourceDirPath += GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.ENTITY_PATH_SUFFIX;
        // 类名
        String className = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName());

        //获取模板
        Template temp = freeMarkerInit.getDefinedTemplate(templatePath, templateName);

        Map<String, Object> root = generatePublicParamMap.get("entityPublicParamMap");

        root.put("className", className);

        templateOutput(temp, root, sourceDirPath, className);

    }

    /**
     * 生成 dto
     * @param generateCodeDto dto
     * @param generatePublicParamMap 公共模板参数
     * @param sourceDirPath 源码输出路径
     * @param templatePath 模板路劲
     * @param templateName 模板文件名
     * @throws IOException io异常
     * @throws TemplateException 模板异常
     */
    public void generateDto(GenerateCodeDto generateCodeDto,
                            Map<String, Map<String, Object>> generatePublicParamMap,
                            String sourceDirPath,
                            String templatePath,
                            String templateName) throws IOException, TemplateException {

        sourceDirPath += GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.DTO_PATH_SUFFIX;
        // 类名
        String className = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName())+ "Dto";

        //获取模板
        Template temp = freeMarkerInit.getDefinedTemplate(templatePath, templateName);

        Map<String, Object> root = generatePublicParamMap.get("dtoPublicParamMap");

        root.put("className", className);

        List<String> importList = new ArrayList<>();
        if (generateCodeDto.getNeedPagination()){

            root.put("needPagination", generateCodeDto.getNeedPagination());
            importList.add("import com.springcloud.common.entity.PageInfo;");

        } else {
            root.put("needPagination", false);
        }
        root.put("importList", importList);

        templateOutput(temp, root, sourceDirPath, className);

    }

    /**
     * 生成 vo
     * @param generateCodeDto dto
     * @param generatePublicParamMap 公共模板参数
     * @param sourceDirPath 源码输出路径
     * @param templatePath 模板路劲
     * @param templateName 模板文件名
     * @throws IOException io异常
     * @throws TemplateException 模板异常
     */
    public void generateVo(GenerateCodeDto generateCodeDto,
                           Map<String, Map<String, Object>> generatePublicParamMap,
                           String sourceDirPath,
                           String templatePath,
                           String templateName) throws IOException, TemplateException {

        sourceDirPath += GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.VO_PATH_SUFFIX;
        // 类名
        String className = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName())+ "Vo";

        //获取模板
        Template temp = freeMarkerInit.getDefinedTemplate(templatePath, templateName);

        Map<String, Object> root = generatePublicParamMap.get("voPublicParamMap");

        root.put("className", className);

        List<String> importList = new ArrayList<>();
        if (generateCodeDto.getNeedPagination()){

            root.put("needPagination", generateCodeDto.getNeedPagination());
            importList.add("import com.springcloud.common.entity.PageInfo;");

        } else {
            root.put("needPagination", false);
        }
        root.put("importList", importList);

        templateOutput(temp, root, sourceDirPath, className);

    }

    /**
     * 生成 dao
     * @param generateCodeDto dto
     * @param generatePublicParamMap 公共模板参数
     * @param sourceDirPath 源码输出路径
     * @param templatePath 模板路劲
     * @param templateName 模板文件名
     * @throws IOException io异常
     * @throws TemplateException 模板异常
     */
    public void generateDao(GenerateCodeDto generateCodeDto,
                            Map<String, Map<String, Object>> generatePublicParamMap,
                            String sourceDirPath,
                            String templatePath,
                            String templateName) throws IOException, TemplateException {
        sourceDirPath += GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.DAO_PATH_SUFFIX;

        // 类名
        String className = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName()) + "Dao";

        //获取模板
        Template temp = freeMarkerInit.getDefinedTemplate(templatePath, templateName);

        Map<String, Object> root = generatePublicParamMap.get("daoPublicParamMap");

        root.put("className", className);

        List<String> importList = new ArrayList<>();
        if (generateCodeDto.getNeedPagination()){

            root.put("needPagination", generateCodeDto.getNeedPagination());
            importList.add("import org.springframework.data.jpa.repository.JpaSpecificationExecutor;");

        } else {
            root.put("needPagination", false);
        }
        String entity = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName());
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"entity"+"."+entity+";");
        root.put("importList", importList);

        OutputStream fos = new FileOutputStream(new File(sourceDirPath, className + ".java"));

        Writer out = new OutputStreamWriter(fos);
        temp.process(root, out);
        fos.flush();
        fos.close();
    }

    /**
     * 生成 service
     * @param generateCodeDto dto
     * @param generatePublicParamMap 公共模板参数
     * @param sourceDirPath 源码输出路径
     * @param templatePath 模板路劲
     * @param templateName 模板文件名
     * @throws IOException io异常
     * @throws TemplateException 模板异常
     */
    public void generateService(GenerateCodeDto generateCodeDto,
                                Map<String, Map<String, Object>> generatePublicParamMap,
                                String sourceDirPath,
                                String templatePath,
                                String templateName) throws IOException, TemplateException {
        sourceDirPath += GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.SERVICE_PATH_SUFFIX;

        // 类名
        String className = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName()) + "Service";

        //获取模板
        Template temp = freeMarkerInit.getDefinedTemplate(templatePath, templateName);

        Map<String, Object> root = generatePublicParamMap.get("servicePublicParamMap");

        root.put("className", className);

        String entity = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName());
        String dto = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName())+"Dto";
        String vo = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName())+"Vo";
        List<String> importList = new ArrayList<>();
        if (generateCodeDto.getNeedPagination()){
            root.put("needPagination", generateCodeDto.getNeedPagination());

            importList.add("import com.springcloud.common.vo.DatePageVO;");

        } else {
            root.put("needPagination", false);
        }
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"entity"+"."+entity+";");
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"dto"+"."+dto+";");
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"vo"+"."+vo+";");
        root.put("importList", importList);

        templateOutput(temp, root, sourceDirPath, className);

    }

    /**
     * 生成 serviceImpl
     * @param generateCodeDto dto
     * @param generatePublicParamMap 公共模板参数
     * @param sourceDirPath 源码输出路径
     * @param templatePath 模板路劲
     * @param templateName 模板文件名
     * @throws IOException io异常
     * @throws TemplateException 模板异常
     */
    public void generateServiceImpl(GenerateCodeDto generateCodeDto,
                                    Map<String, Map<String, Object>> generatePublicParamMap,
                                    String sourceDirPath,
                                    String templatePath,
                                    String templateName) throws IOException, TemplateException {
        sourceDirPath += GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.SERVICE_IMPL_PATH_SUFFIX;

        // 类名
        String className = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName()) + "ServiceImpl";

        //获取模板
        Template temp = freeMarkerInit.getDefinedTemplate(templatePath, templateName);

        Map<String, Object> root = generatePublicParamMap.get("serviceImplPublicParamMap");

        root.put("className", className);

        String entity = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName());
        String dto = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName())+"Dto";
        String vo = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName())+"Vo";
        String dao = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName())+"Dao";
        String service = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName())+"Service";

        List<String> importList = new ArrayList<>();
        if (generateCodeDto.getNeedPagination()){
            root.put("needPagination", generateCodeDto.getNeedPagination());

            importList.add("import org.springframework.data.domain.Page;");
            importList.add("import org.springframework.data.domain.PageRequest;");
            importList.add("import org.springframework.data.domain.Pageable;");
            importList.add("import org.springframework.data.domain.Sort;");
            importList.add("import org.springframework.data.jpa.domain.Specification;");
            importList.add("import org.springframework.data.domain.Page;");
            importList.add("import javax.persistence.criteria.Predicate;");


            importList.add("import com.springcloud.common.vo.DatePageVO;");
            root.put("needPagination", true);
        } else {
            root.put("needPagination", false);
        }
        importList.add("import com.springcloud.common.utils.BeanCopyUtil;");
        importList.add("import org.springframework.util.StringUtils;");
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"entity"+"."+entity+";");
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"dto"+"."+dto+";");
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"vo"+"."+vo+";");
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"dao"+"."+dao+";");
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"service"+"."+service+";");
        root.put("importList", importList);

        List<FieldInfo> fieldInfoList = new ArrayList<>();
        for (FieldInfo fieldInfo: generateCodeDto.getTableFieldList()) {
            if (fieldInfo.getPaginationQueryCondition()){
                FieldInfo fieldInfoCopy = new FieldInfo();
                BeanCopyUtil.copyProperties(fieldInfo, fieldInfoCopy);
                fieldInfoCopy.setJavaGetterORSetterColumnName(FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(fieldInfoCopy.getDbColumnName()));
                fieldInfoList.add(fieldInfoCopy);
            }
        }
        root.put("pageQueryConditionFieldList", fieldInfoList);

        templateOutput(temp, root, sourceDirPath, className);

    }

    /**
     * 生成 controller
     * @param generateCodeDto dto
     * @param generatePublicParamMap 公共模板参数
     * @param sourceDirPath 源码输出路径
     * @param templatePath 模板路劲
     * @param templateName 模板文件名
     * @throws IOException io异常
     * @throws TemplateException 模板异常
     */
    public void generateController(GenerateCodeDto generateCodeDto,
                                   Map<String, Map<String, Object>> generatePublicParamMap,
                                   String sourceDirPath,
                                   String templatePath,
                                   String templateName) throws IOException, TemplateException {
        sourceDirPath += GenerateSuffixConstants.PATH_SIGN_SUFFIX + GenerateSuffixConstants.CONTROLLER_PATH_SUFFIX;

        // 类名
        String className = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName()) + "Controller";

        //获取模板
        Template temp = freeMarkerInit.getDefinedTemplate(templatePath, templateName);

        Map<String, Object> root = generatePublicParamMap.get("controllerPublicParamMap");


        root.put("className", className);

        String entity = (String) root.get("entity");
        String entityDto = (String) root.get("entityDto");
        String entityVo = (String) root.get("entityVo");
        String entityService = (String) root.get("entityService");

        List<String> importList = new ArrayList<>();
        if (generateCodeDto.getNeedPagination()){
            root.put("needPagination", generateCodeDto.getNeedPagination());

            importList.add("import com.springcloud.common.vo.DatePageVO;");
            root.put("needPagination", true);
        } else {
            root.put("needPagination", false);
        }

        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"entity"+"."+entity+";");
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"dto"+"."+entityDto+";");
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"vo"+"."+entityVo+";");
        importList.add("import "+ generateCodeDto.getPackagePath()+"."+"service"+"."+entityService+";");

        root.put("importList", importList);

        List<FieldInfo> fieldInfoList = new ArrayList<>();
        for (FieldInfo fieldInfo: generateCodeDto.getTableFieldList()) {
            if (fieldInfo.getPaginationQueryCondition()){
                FieldInfo fieldInfoCopy = new FieldInfo();
                BeanCopyUtil.copyProperties(fieldInfo, fieldInfoCopy);
                fieldInfoCopy.setJavaGetterORSetterColumnName(FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(fieldInfoCopy.getDbColumnName()));
                fieldInfoList.add(fieldInfoCopy);
            }
        }
        root.put("pageQueryConditionFieldList", fieldInfoList);

        templateOutput(temp, root, sourceDirPath, className);

    }

    /**
     * 源码输出
     * @param temp 模板
     * @param root 模板数据map
     * @param sourceDirPath 输出源码的路径
     * @param className 输出源码的文件名
     * @throws IOException io 异常
     * @throws TemplateException 模板异常
     */
    public void templateOutput(Template temp,
                               Map<String, Object> root,
                               String sourceDirPath,
                               String className) throws IOException, TemplateException {
        OutputStream fos = new FileOutputStream(new File(sourceDirPath, className + ".java"));

        Writer out = new OutputStreamWriter(fos);
        temp.process(root, out);
        fos.flush();
        fos.close();
    }

    /**
     * 公共模板参数
     * @param generateCodeDto dto
     * @return Map<String, Map<String, Object>>
     */
    public Map<String, Map<String, Object>> generatePublicParam(GenerateCodeDto generateCodeDto) {

        ZonedDateTime now = ZonedDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss");
        String formatterDate = now.format(formatter);
        Map<String, Map<String, Object>> generatePublicParamMap = new HashMap<>();

        // PackagePath start
        String entityPackagePath = generateCodeDto.getPackagePath() + "." + "entity";
        String dtoPackagePath = generateCodeDto.getPackagePath() + "." + "dto";
        String voPackagePath = generateCodeDto.getPackagePath() + "." + "vo";
        String daoPackagePath = generateCodeDto.getPackagePath() + "." + "dao";
        String servicePackagePath = generateCodeDto.getPackagePath() + "." + "service";
        String serviceImplPackagePath = generateCodeDto.getPackagePath() + "." + "service" + "." + "impl";
        String controllerPackagePath = generateCodeDto.getPackagePath() + "." + "web";
        // PackagePath end

        // className and classParam start
        String entity = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName());
        String entityParam = FieldConvertJavaHumpUtils.firstCodeLowerCaseConvertJavaHump(generateCodeDto.getTableName());
        String entityVo = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName()) + "Vo";
        String entityVoParam = FieldConvertJavaHumpUtils.firstCodeLowerCaseConvertJavaHump(generateCodeDto.getTableName()) + "Vo";
        String entityDto = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName()) + "Dto";
        String entityDtoParam = FieldConvertJavaHumpUtils.firstCodeLowerCaseConvertJavaHump(generateCodeDto.getTableName()) + "Dto";
        String entityDao = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName()) + "Dao";
        String entityDaoParam = FieldConvertJavaHumpUtils.firstCodeLowerCaseConvertJavaHump(generateCodeDto.getTableName()) + "Dao";
        String entityService = FieldConvertJavaHumpUtils.firstCodeUpperConvertJavaHump(generateCodeDto.getTableName()) + "Service";
        String entityServiceParam = FieldConvertJavaHumpUtils.firstCodeLowerCaseConvertJavaHump(generateCodeDto.getTableName()) + "Service";
        // className and classParam end

        // entityPublicParamMap
        HashMap<String, Object> entityPublicParamMap = new HashMap<>();
        entityPublicParamMap.put("packagePath", entityPackagePath);
        entityPublicParamMap.put("fieldList", generateCodeDto.getTableFieldList());
        entityPublicParamMap.put("generateDate", formatterDate);
        generatePublicParamMap.put("entityPublicParamMap", entityPublicParamMap);

        // dtoPublicParamMap
        HashMap<String, Object> dtoPublicParamMap = new HashMap<>();
        dtoPublicParamMap.put("packagePath", dtoPackagePath);
        dtoPublicParamMap.put("fieldList", generateCodeDto.getTableFieldList());
        dtoPublicParamMap.put("generateDate", formatterDate);
        generatePublicParamMap.put("dtoPublicParamMap", dtoPublicParamMap);


        // voPublicParamMap
        HashMap<String, Object> voPublicParamMap = new HashMap<>();
        voPublicParamMap.put("packagePath", voPackagePath);
        voPublicParamMap.put("fieldList", generateCodeDto.getTableFieldList());
        voPublicParamMap.put("generateDate", formatterDate);
        generatePublicParamMap.put("voPublicParamMap", voPublicParamMap);

        // daoPublicParamMap
        HashMap<String, Object> daoPublicParamMap = new HashMap<>();
        daoPublicParamMap.put("packagePath", daoPackagePath);
        daoPublicParamMap.put("entity", entity);
        daoPublicParamMap.put("entityParam", entityParam);
        daoPublicParamMap.put("generateDate", formatterDate);
        generatePublicParamMap.put("daoPublicParamMap", daoPublicParamMap);

        // servicePublicParamMap
        HashMap<String, Object> servicePublicParamMap = new HashMap<>();
        servicePublicParamMap.put("packagePath", servicePackagePath);
        servicePublicParamMap.put("entity", entity);
        servicePublicParamMap.put("entityVo", entityVo);
        servicePublicParamMap.put("entityDto", entityDto);
        servicePublicParamMap.put("entityDtoParam", entityDtoParam);
        servicePublicParamMap.put("generateDate", formatterDate);
        generatePublicParamMap.put("servicePublicParamMap", servicePublicParamMap);

        // serviceImplPublicParamMap
        HashMap<String, Object> serviceImplPublicParamMap = new HashMap<>();
        serviceImplPublicParamMap.put("packagePath", serviceImplPackagePath);
        serviceImplPublicParamMap.put("entity", entity);
        serviceImplPublicParamMap.put("entityParam", entityParam);
        serviceImplPublicParamMap.put("entityVo", entityVo);
        serviceImplPublicParamMap.put("entityVoParam", entityVoParam);
        serviceImplPublicParamMap.put("entityDto", entityDto);
        serviceImplPublicParamMap.put("entityDtoParam", entityDtoParam);
        serviceImplPublicParamMap.put("entityDao", entityDao);
        serviceImplPublicParamMap.put("entityDaoParam", entityDaoParam);
        serviceImplPublicParamMap.put("entityService", entityService);
        serviceImplPublicParamMap.put("generateDate", formatterDate);
        generatePublicParamMap.put("serviceImplPublicParamMap", serviceImplPublicParamMap);

        // controllerPublicParamMap
        HashMap<String, Object> controllerPublicParamMap = new HashMap<>();
        ;
        controllerPublicParamMap.put("packagePath", controllerPackagePath);
        controllerPublicParamMap.put("entity", entity);
        controllerPublicParamMap.put("entityParam", entityParam);
        controllerPublicParamMap.put("entityVo", entityVo);
        controllerPublicParamMap.put("entityVoParam", entityVoParam);
        controllerPublicParamMap.put("entityDto", entityDto);
        controllerPublicParamMap.put("entityDtoParam", entityDtoParam);
        controllerPublicParamMap.put("entityService", entityService);
        controllerPublicParamMap.put("entityServiceParam", entityServiceParam);
        controllerPublicParamMap.put("generateDate", formatterDate);

        generatePublicParamMap.put("controllerPublicParamMap", controllerPublicParamMap);

        return generatePublicParamMap;
    }
}
